package scfg.utils.training_set_filter;

import scfg.AlignedSequence;
import scfg.CYK;
import scfg.Grammar;
import scfg.KHGrammar;
import scfg.PfoldGrammar;
import scfg.RNAStatsObj;
import scfg.RnaAlgoPrediction;
import scfg.output.Display;
import scfg.output.database.DatabaseHandler;
import scfg.output.flot.HtmlTemplateObject;
import scfg.output.flot.flot;
import scfg.output.flot.flotInt;
import scfg.output.flot.flotSingle;
import scfg.output.ggobi.ggobi;
import scfg.output.ggobi.ggobiVariable;
import scfg.utils.Compare;
import scfg.utils.MfeAquire;
import scfg.utils.NativeStructureAligner;
import scfg.utils.trainging_results.delete.TrainingResultsParser;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;

import com.mysql.jdbc.MysqlDefs;

import desposito6.math.MyBigDecimal;
import desposito6.math.iDouble;
import desposito6.utils.CommandLine;

public class CustomPlotAnalysis {
	
	public static void plot3DKHProductions(List<List<AlignedSequence>>[] traingingSetsArr, String outFilename) {
		if (traingingSetsArr == null || outFilename == null)
			return;
		if (!outFilename.endsWith(".dat"))
			outFilename += ".dat";
		Display output = new Display(outFilename, null, false);
		output.out("(p1=S->SL)	(q1=S->L)	(p2=L->dFf')	(q2=L->s)	(p3=F->dFd')	(q3=F->LS)	color(group)");
		Grammar g;
		for (int k=0;k<3;k++) {
			List<List<AlignedSequence>> traingingSets = traingingSetsArr[k];
			for (int i=0;i<traingingSets.size();i++){
				List<AlignedSequence> currSet = traingingSets.get(i);
				g = new KHGrammar();
				for (AlignedSequence seq : currSet){
					String nat = seq.getStructure("refrence").getStructure();
					String nSeq = seq.getSequence();
					if (nat != null && nSeq != null) {
						g.add(nat, nSeq);
					} else
						System.err.println("Error in set: " + i + " - " + seq.getName());
				}
				writeKHProducitons(output, g, k, currSet.size());
			}
		}
		output.finalizeDisplay();
	}
	
	public static void flotGrammarProbabilities(List<List<AlignedSequence>>[] traingingSetsArr, String htmlOut, String jsOut, String plotTitle) {
		// TODO
		if (traingingSetsArr == null || htmlOut == null || jsOut == null)
			return;
		if (!htmlOut.endsWith(".html"))
			htmlOut += ".html";
		if (!jsOut.endsWith(".js"))
			jsOut += ".js";
		flotInt iFlot = new flotInt();
		Grammar g;
		for (int k=0;k<3;k++) {
			List<List<AlignedSequence>> traingingSets = traingingSetsArr[k];
			for (int i=0;i<traingingSets.size();i++){
				List<AlignedSequence> currSet = traingingSets.get(i);
				g = new PfoldGrammar();
				for (AlignedSequence seq : currSet){
					String nat = seq.getStructure("refrence").getStructure();
					String nSeq = seq.getSequence();
					if (nat != null && nSeq != null) {
						g.add(nat, nSeq);
					} else
						System.err.println("Error in set: " + i + " - " + seq.getName());
				}
				String keyName = (k == 0 ? "Easy " : (k == 1 ? "Medium " : "Hard ")) + "training set " + i;
				iFlot.addKey(keyName);
				addFlotVals2D(g.get_kh_params(), Grammar.kh_params_names, iFlot, k, true);
				addFlotVals2D(g.get_nucleotide_dist(), Grammar.kh_nucleotide_names, iFlot, k, false);
				addFlotVals3D(g.get_pfold_params_p(), Grammar.pfold_basePair_names, iFlot, k);
			}
		}
		flot.outToJsFileInt(iFlot, new Display(jsOut, null, false));
		String[] arr = jsOut.split("/");
		flot.outToHtml(new HtmlTemplateObject(plotTitle, "", arr[arr.length-1], flot.generateTableHtml(iFlot.getSeries()), flot.TEMPLATE), new Display(htmlOut, null, false));
	}
	
	private static void addFlotVals2D(iDouble[] arr, String[] names, flotInt flot, int subset, boolean doMinusOne) {
		for (int i=0;i<arr.length;i++)
			flot.addValue(names[i], subset, arr[i].toPlainString());
		if (doMinusOne) {
			iDouble one = new MyBigDecimal(1);
			for (int i=0;i<arr.length;i++)
				flot.addValue(names[i+arr.length], subset, one.sub(arr[i]).toPlainString());
		}
	}
	
	private static void addFlotVals3D(iDouble[][] arr, String[][] names, flotInt flot, int subset) {
		for (int i=0;i<arr.length;i++) 
			for (int j=0;j<arr[i].length;j++)
				flot.addValue(names[i][j], subset, arr[i][j].toPlainString());
	}
	
	private static void writeKHProducitons(Display output, Grammar g, int color, int count) {
		/* 
		 * q1 = p(S->L)   = probs[0]
		 * p1 = p(S->LS)  = 1 - probs[0]
		 * q2 = p(L->s)   = probs[1] 
		 * q2 = p(L->dFd) = 1 - probs[1] 
		 * p3 = p(F->LS)  = probs[2] 
		 * q3 = p(F->dFd) = 1 - probs[2]
		 */
		iDouble[] arr = g.get_kh_params();
		iDouble one = new MyBigDecimal(1);
		iDouble p1 = one.sub(arr[0]); 	// S -> LS
		iDouble q1 = arr[0];			// S -> L
		iDouble p2 = one.sub(arr[1]);	// L -> dFd'
		iDouble q2 = arr[1];			// L -> s
		iDouble p3 = one.sub(arr[2]);	// F -> dFd'
		iDouble q3 = arr[2];			// F -> LS
		
		output.outC(Display.buf(p1.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(q1.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(p2.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(q2.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(p3.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(q3.toPlainString(), 10, ' ')).outC("\t");
		output.out("" + color);
	}
	
	public static void plotConnocialProportionRatio(List<List<AlignedSequence>>[] traingingSetsArr, String outFilename) {
		if (traingingSetsArr == null || outFilename == null)
			return;
		if (!outFilename.endsWith(".dat"))
			outFilename += ".dat";
		Display output = new Display(outFilename, null, false);
		output.out("(NonConBpRatio)	(ConBpRatio)	color(group)");
		Grammar g;
		for (int k=0;k<3;k++) {
			List<List<AlignedSequence>> traingingSets = traingingSetsArr[k];
			for (int i=0;i<traingingSets.size();i++){
				List<AlignedSequence> currSet = traingingSets.get(i);
				int conBPs = 0;
				int nonConBPs = 0;
				int seqLens = 0;
				for (AlignedSequence seq : currSet){
					RNAStatsObj stats = new RNAStatsObj(seq.getName(), seq.getSequence(), seq.getStructure("refrence").getStructure(), seq.getStructure("mfe_GTFold").getStructure(), seq.getStructure("mfe_GTFoldX").getStructure(), seq.getStructure("mfe_gt").getStructure());
					if (stats.getNatCanonicalBasePairs() != null && stats.getNatBasePairs() != null) {
						conBPs += stats.getNatCanonicalBasePairs();
						nonConBPs += stats.getNatNonCanonicalBasePairs();
						seqLens += stats.getSequenceLength();
					} else
						System.err.println("Error in set: " + i + " - " + seq.getName());
				}
				writeConinicalRatios(output, conBPs, nonConBPs, seqLens, k);
			}
		}
		output.finalizeDisplay();
	}
	
	private static void writeConinicalRatios(Display output, int conBPs, int nonConBPs, int seqLen, int color) {
		iDouble conRatio = new MyBigDecimal(conBPs).div(seqLen);
		iDouble nonConRatio = new MyBigDecimal(nonConBPs).div(seqLen);
		
		output.outC(Display.buf(nonConRatio.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(conRatio.toPlainString(), 10, ' ')).outC("\t");
		output.out("" + color);
	}
	

	
	public static void plotBasepairProportionRatio(List<List<AlignedSequence>>[] traingingSetsArr, String outFilename) {
		if (traingingSetsArr == null || outFilename == null)
			return;
		if (!outFilename.endsWith(".dat"))
			outFilename += ".dat";
		Display output = new Display(outFilename, null, false);
		output.out("(NonConBpRatio)	(WcBpRatio)	(WbBpRatio)	color(group)");
		for (int k=0;k<3;k++) {
			List<List<AlignedSequence>> traingingSets = traingingSetsArr[k];
			for (int i=0;i<traingingSets.size();i++){
				List<AlignedSequence> currSet = traingingSets.get(i);
				int wcConBPs = 0;
				int wbConBPs = 0;
				int nonConBPs = 0;
				int seqLens = 0;
				for (AlignedSequence seq : currSet){
					RNAStatsObj stats = new RNAStatsObj(seq.getName(), seq.getSequence(), seq.getStructure("refrence").getStructure(), seq.getStructure("mfe_GTFold").getStructure(), seq.getStructure("mfe_GTFoldX").getStructure(), seq.getStructure("mfe_gt").getStructure());
					if (stats.getNatCanonicalBasePairs() != null && stats.getNatBasePairs() != null) {
						wcConBPs += stats.getNatWcBasePairs();
						wbConBPs += stats.getNatWbBasePairs();
						nonConBPs += stats.getNatNonCanonicalBasePairs();
						seqLens += stats.getSequenceLength();
					} else
						System.err.println("Error in set: " + i + " - " + seq.getName());
				}
				writeBPRatios(output, wcConBPs, wbConBPs, nonConBPs, seqLens, k);
			}
		}
		output.finalizeDisplay();
	}
	
	private static void writeBPRatios(Display output, int wcConBPs, int wbConBPs, int nonConBPs, int seqLen, int color) {
		iDouble wcRatio = new MyBigDecimal(wcConBPs).div(seqLen);
		iDouble wbRatio = new MyBigDecimal(wbConBPs).div(seqLen);
		iDouble nonConRatio = new MyBigDecimal(nonConBPs).div(seqLen);

		output.outC(Display.buf(nonConRatio.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(wcRatio.toPlainString(), 10, ' ')).outC("\t");
		output.outC(Display.buf(wbRatio.toPlainString(), 10, ' ')).outC("\t");
		output.out("" + color);
	}
	
	private static Map<String, Integer> checkCFGCountRelationship(List<List<AlignedSequence>> traingingSets) {
		int totalS = 0;
		int totalL_t = 0;
		int total = 0;
		int matches = 0;
		int maxDiff = 0;
		Grammar g;
		for (int i=0;i<traingingSets.size();i++){
			List<AlignedSequence> currSet = traingingSets.get(i);
			g = new KHGrammar();
			Map<String, Integer> counts;
			for (AlignedSequence seq : currSet){
				String nat = seq.getStructure("refrence").getStructure();
				String nSeq = seq.getSequence();
				if (nat != null && nSeq != null) {
					g.add(nat, nSeq);
				} else
					System.err.println("Error in set: " + i + " - " + seq.getName());
				counts = g.getCountsArray();
				if (!counts.get("S").equals(counts.get("L_s")))
					break;
			}
			counts = g.getCountsArray();
			total++;
			if (counts.get("S").equals(counts.get("L_s")))
				matches++;
			totalS += counts.get("S");
			totalL_t += counts.get("L_s");
			maxDiff = Math.max(maxDiff, Math.abs(counts.get("S") - counts.get("L_s")));
		}
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("# Sets   ", total);
		map.put("c(S)     ", totalS);
		map.put("c(L_t)   ", totalL_t);
		map.put("Matches  ", matches);
		map.put("Max Diff ", maxDiff);
		return map;
	}
	
	public static void printCFGCountRelationship(List<List<AlignedSequence>>[] traingingSetsArr, String rnaClass) {
		if (traingingSetsArr == null)
			return;
		String[] arr = new String[] { "Easy:", "Medium:", "Hard:" };
		for(int i=0;i<traingingSetsArr.length;i++) {
			Map<String, Integer> map = checkCFGCountRelationship(traingingSetsArr[i]);
			System.out.println(Display.underline(rnaClass + arr[i], ""));
//			for (Entry<String, Integer> me : map.entrySet()){
//				System.out.println(me.getKey() + ":\t" + me.getValue());
//			}
			printCFGCountRelationShip(map);
		}
	}
	
	private static void printCFGCountRelationShip(Map<String, Integer> map) {
		System.out.println("# Sets   " + map.get("# Sets   "));
		System.out.println("c(S)     " + map.get("c(S)     "));
		System.out.println("c(L->t)  " + map.get("c(L_t)   "));
		System.out.println("Matches  " + map.get("Matches  "));
		System.out.println("Max Diff " + map.get("Max Diff "));
		System.out.println("\n****************************\n");
	}
	
	//c(L->dFd) = c(F->LS) = c(S-L) - 1
	//for all training sets.
	private static Map<String, Integer> checkCFGCountRelationship2(List<List<AlignedSequence>> traingingSets) {
		int totalS_L = 0;
		int totalL_dFd = 0;
		int totalF_LS = 0;
		int total = 0;
		int matchesSL = 0;
		int matchesSF = 0;
		int matchesLF = 0;
		Grammar g;
		for (int i=0;i<traingingSets.size();i++){
			List<AlignedSequence> currSet = traingingSets.get(i);
			g = new KHGrammar();
			Map<String, Integer> counts;
			int j = 0;
			for (AlignedSequence seq : currSet){
				String nat = seq.getStructure("refrence").getStructure();
				String nSeq = seq.getSequence();
				if (nat != null && nSeq != null) {
					g.add(nat, nSeq);
				} else
					System.err.println("Error in set: " + i + " - " + seq.getName());
				counts = g.getCountsArray();
				if (!counts.get("L_dFd").equals(counts.get("F_LS")))
					break;
				if (!counts.get("L_dFd").equals(counts.get("S_L") - (j++) - 1))
					break;
			}
			counts = g.getCountsArray();
			total++;
			counts = g.getCountsArray();
			if (counts.get("L_dFd").equals(counts.get("F_LS")))
				matchesLF++;
			if (counts.get("L_dFd").equals(counts.get("S_L") - currSet.size()))
				matchesSL++;
			if (counts.get("F_LS").equals(counts.get("S_L") - currSet.size()))
				matchesSF++;
			totalS_L += counts.get("S_L");
			totalL_dFd += counts.get("L_dFd");
			totalF_LS += counts.get("F_LS");
		}
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("# Sets    ", total);
		map.put("c(S->L)   ", totalS_L);
		map.put("c(L->dFd) ", totalL_dFd);
		map.put("c(F->LS)  ", totalF_LS);
		map.put("S and L   ", matchesSL);
		map.put("S and F   ", matchesSF);
		map.put("L and F   ", matchesLF);
		return map;
	}
	
	public static void printCFGCountRelationship2(List<List<AlignedSequence>>[] traingingSetsArr, String rnaClass) {
		if (traingingSetsArr == null)
			return;
		String[] arr = new String[] { "Easy:", "Medium:", "Hard:" };
		for(int i=0;i<traingingSetsArr.length;i++) {
			Map<String, Integer> map = checkCFGCountRelationship2(traingingSetsArr[i]);
			System.out.println(Display.underline(rnaClass + arr[i], ""));
//			for (Entry<String, Integer> me : map.entrySet()){
//				System.out.println(me.getKey() + ":\t" + me.getValue());
//			}
			printCFGCountRelationShip2(map);
		}
	}
	
	private static void printCFGCountRelationShip2(Map<String, Integer> map) {
		System.out.println("# Sets    " + map.get("# Sets    "));
		System.out.println("c(S->L)   " + map.get("c(S->L)   "));
		System.out.println("c(L->dFd) " + map.get("c(L->dFd) "));
		System.out.println("c(F->LS)  " + map.get("c(F->LS)  "));
		System.out.println("::Matches::");
		System.out.println("S and L   " + map.get("S and L   "));
		System.out.println("S and F   " + map.get("S and F   "));
		System.out.println("L and F   " + map.get("L and F   "));
		System.out.println("\n******************************\n");
	}
	
	public static void printCountsAndUnion(List<AlignedSequence> seqs, Display out){
//		List<Map<String, Integer>> maps = new LinkedList<Map<String, Integer>>();
		Map<String, Integer> union = new HashMap<String, Integer>();
		for (AlignedSequence seq : seqs){
			Map<String, Integer> counts = getCounts(seq);
//			maps.add(counts);
			printSeqCounts(out, seq.getName(), counts);
			unionMaps(union, counts);
		}
		printSeqCounts(out, "Union", union);
	}
	
	private static void unionMaps(Map<String, Integer> dest, Map<String,Integer> src){
		for(Entry<String, Integer> me : src.entrySet()){
			if (dest.get(me.getKey()) == null)
				dest.put(me.getKey(), 0);
			dest.put(me.getKey(), dest.get(me.getKey()) + src.get(me.getKey()));
		}
	}
	
	private static void printSeqCounts(Display out, String header, Map<String, Integer> counts){
		out.out(Display.underline(header, ""));
		for(Entry<String,Integer> me : counts.entrySet())
			out.out(Display.buf(me.getKey(), 5, ' ') + Display.buf(me.getValue().toString(), 5, ' '));
	}
	
	private static Map<String, Integer> getCounts(AlignedSequence seq) {
		Grammar g = new KHGrammar();
		g.add(seq.getStructure("refrence").getStructure(), seq.getSequence());
		return g.getCountsArray();
	}
	
	public static void generatePredictionPlot(List<AlignedSequence>[] traingingSetsArr, String outFilename) {
		if (traingingSetsArr == null || outFilename == null)
			return;
		if (!outFilename.endsWith(".dat"))
			outFilename += ".dat";
		Display output = new Display(outFilename, null, false);
		output.out("(MFE F-M)	(Pfold F-M)	color(group)");
		for (int k=2;k<3;k++) {
			List<AlignedSequence> traingingSet = traingingSetsArr[k];
			PfoldGrammar g = new PfoldGrammar();
			for (AlignedSequence seq : traingingSet){
				g.add(seq.getStructure("refrence").getStructure(), seq.getSequence());
			}
			double avgMFE = 0;
			double avgPfold = 0;
			int count = 0;
			for (AlignedSequence seq : traingingSet){
				System.out.println(Display.box((++count) + "", "\t"));
				String pred = CYK.predictFromGrammar(seq.getSequence(), g);  
				avgMFE = Compare.getFMeasure(seq.getStructure("refrence").getStructure(), seq.getStructure("mfe_gt").getStructure());
				avgPfold = Compare.getFMeasure(seq.getStructure("refrence").getStructure(), pred);
				writePredictionRow(avgMFE, avgPfold, k, output);
			}
		}
		output.finalizeDisplay();
	}
	
	private static void writePredictionRow(double mfe, double pfold, int color, Display output) {
		output.outC(Display.buf("" + mfe, 8, ' ')).outC("\t");
		output.outC(Display.buf("" + pfold, 8, ' ')).outC("\t");
		output.out(color + "");
	}
	
	public static void plotPercentIdentityFMeasureComparison(List<AlignedSequence> seqs, String outFilename, double identityThreshold) {
		if (seqs == null || outFilename == null)
			return;
		if (!outFilename.endsWith(".dat"))
			outFilename += ".dat";
		Display output = new Display(outFilename, null, false);
		output.out("(MFE1)\t(MFE2)\tcol");
		Collection<String> processed = new HashSet<String>();
		Long start = System.currentTimeMillis();
		CommandLine.DisplayBar(0, 0);
		int count = 0;
		for (AlignedSequence seq1 : seqs) {
			CommandLine.DisplayBar((int)(((double)(count++) / (double)seqs.size())*100), (int)((System.currentTimeMillis() - start) / 1000));
			for(AlignedSequence seq2 : seqs) {
				System.out.print(".");
				if (!processed.contains(getCustomASKey(seq1, seq2)) && !seq1.equals(seq2)){
					processed.add(getCustomASKey(seq1, seq2));
					if (seq1.getAlignment() == null || seq2.getAlignment() == null) {
						if (seq1.getAlignment() == null)
							System.err.print(seq1.getName());
						else if (seq2.getAlignment() == null)
							System.err.print(seq2.getName());
					} else {
						double idenity = IdenityFilter.percentIdentity3(seq1.getAlignment(), seq2.getAlignment());
						if (idenity >= identityThreshold){
							if (seq1.getStructure("mfe_gt") == null)
								UpdateGtFoldPrediction(seq1);
							if (seq2.getStructure("mfe_gt") == null)
								UpdateGtFoldPrediction(seq2);
							double seq1FM = Compare.getFMeasure(seq1.getStructure("refrence").getStructure(), seq1.getStructure("mfe_gt").getStructure());
							double seq2FM = Compare.getFMeasure(seq2.getStructure("refrence").getStructure(), seq2.getStructure("mfe_gt").getStructure());
							output.outC(Display.buf(""+seq1FM, 10, ' ')).outC(Display.buf(""+seq2FM, 10, ' '));
							output.out("\t" + convertIdenityColor(idenity));
							if (Math.abs(seq1FM - seq2FM) > 0.2) {
								File dir = new File("jViz/jVizComp_" + Display.buf(""+(seq1FM - seq2FM), 10, ' ') + "_" + seq1.getName() + "_vs_" + seq2.getName());
								if (!dir.exists()) dir.mkdirs();
								String[] arr = NativeStructureAligner.alignNativeSequences(seq1, seq2);
								String fname = dir.getAbsolutePath() + "/" + seq1.getName() + "_1.txt";
								StringBuilder sb = new StringBuilder();
								sb.append(">").append(seq1.getName()).append(": ").append(seq1.getFMeasure()).append("\nseq: ").append(arr[0]);
								sb.append("\nnat: ").append(arr[1]).append("\nmfe: ").append(arr[2]).append("\n");
								new Display(fname, null, false).out(sb.toString()).finalizeDisplay();
								Display bothStructure = new Display(dir.getAbsolutePath() + "/both.txt", null, false);
								bothStructure.outC("% Identity: ").out(idenity + "\n");
								bothStructure.out(sb.toString());
								sb = new StringBuilder();
								fname = dir.getAbsolutePath() + "/" + seq2.getName() + "_2.txt";
								sb.append(">").append(seq2.getName()).append(": ").append(seq2.getFMeasure()).append("\nseq: ").append(arr[3]);
								sb.append("\nnat: ").append(arr[4]).append("\nmfe: ").append(arr[5]);
								new Display(fname, null, false).out(sb.toString()).finalizeDisplay();
								bothStructure.out(sb.toString()).finalizeDisplay();
							}
						}
					}
				}
			}
		}
		CommandLine.DisplayBarFinish();
		output.finalizeDisplay();
	}
	
	public static void flotPercentIdentityFMeasureComparison(List<AlignedSequence> seqs, String htmlOut, String jsOut, double identityThreshold) {
		if (seqs == null || htmlOut == null || jsOut == null)
			return;
		if (!htmlOut.endsWith(".html"))
			htmlOut += ".html";
		if (!jsOut.endsWith(".js"))
			jsOut += ".js";
		flotSingle sing = new flotSingle("%Iden. F-Measure Comparison");
		Collection<String> processed = new HashSet<String>();
		Long start = System.currentTimeMillis();
		CommandLine.DisplayBar(0, 0);
		int count = 0;
		for (AlignedSequence seq1 : seqs) {
			CommandLine.DisplayBar((int)(((double)(count++) / (double)seqs.size())*100), (int)((System.currentTimeMillis() - start) / 1000));
			for(AlignedSequence seq2 : seqs) {
				System.out.print(".");
				if (!processed.contains(getCustomASKey(seq1, seq2)) && !seq1.equals(seq2)){
					processed.add(getCustomASKey(seq1, seq2));
					if (seq1.getAlignment() == null || seq2.getAlignment() == null) {
						if (seq1.getAlignment() == null)
							System.err.print(seq1.getName());
						else if (seq2.getAlignment() == null)
							System.err.print(seq2.getName());
					} else {
						double idenity = IdenityFilter.percentIdentity3(seq1.getAlignment(), seq2.getAlignment());
						if (idenity >= identityThreshold){
							if (seq1.getStructure("mfe_gt") == null)
								UpdateGtFoldPrediction(seq1);
							if (seq2.getStructure("mfe_gt") == null)
								UpdateGtFoldPrediction(seq2);
							double seq1FM = Compare.getFMeasure(seq1.getStructure("refrence").getStructure(), seq1.getStructure("mfe_gt").getStructure());
							double seq2FM = Compare.getFMeasure(seq2.getStructure("refrence").getStructure(), seq2.getStructure("mfe_gt").getStructure());
							sing.addPair(Display.buf(""+seq1FM, 10, ' ').trim(), Display.buf(""+seq2FM, 10, ' ').trim());
							sing.addKey(seq1.getName() + " vs. " + seq2.getName());
						}
					}
				}
			}
		}
		CommandLine.DisplayBarFinish();
		flot.outToJsFileSingle(sing, new Display(jsOut, null, false));
		String[] jsOutArr = jsOut.split("/");
		flot.outToHtml(new HtmlTemplateObject("Percent Identity: F-Measure Comparison", "", jsOutArr[jsOutArr.length-1], "", flot.TEMPLATE), new Display(htmlOut, null, false));
	}
	
	private static void UpdateGtFoldPrediction(AlignedSequence seq) {
		System.out.print("\nGetting GtFold Prediction: " + seq.getName() +"...");
		new Display("sequences/" + seq.getName()+".seq", null, false).out(seq.getSequence()).finalizeDisplay();
		File f = new File("sequences/" + seq.getName()+".seq");
		while(!f.exists() || f.length() < 10);
		seq.addStructure(new RnaAlgoPrediction("mfe_gt", MfeAquire.getGTfoldDBStructure("sequences/" + seq.getName() + ".seq")));
		System.out.print(" " + seq.getStructure("mfe_gt"));
		DatabaseHandler.updateAlignedSequence(seq);
		System.out.println(" Prediction Finished");
	}
	
	private static String getCustomASKey(AlignedSequence s1, AlignedSequence s2) {
		if (s1 == null || s2 == null)
			return "";
		if (s1.getName().compareTo(s2.getName()) <= 0)
			return s1.getName() + s2.getName();
		return s2.getName() + s1.getName();
	}
	
	private static int convertIdenityColor(double d) {
		double a1 = d - 0.8;
		double a2 = 0.95 / 0.2;
		double b = a1 * a2;
		b += 0.05;
		double c = b * 245;
		int rtn = 255 - (int)c;
		return (255 << 16) | (rtn << 8) | rtn;
	}
	
	public static void densityFmeasureComparison(List<AlignedSequence> seqs, Display out) {
		if (seqs == null || out == null) {
			return;
		}
		out.out("Dens\tDensComp\tFMsr");
		for(AlignedSequence seq : seqs) {
			out.outC(seq.getDenseString()).outC("\t").outC(seq.getDenseCompString()).outC("\t").out(seq.getFMeasureString());
		}
		out.finalizeDisplay();
	}
	
	public static void outputGgobiXMLGrammar(List<List<AlignedSequence>>[] seqSets, Display out) {
		if (seqSets == null || out == null)
			return;
		List<Grammar> easyGrams = new LinkedList<Grammar>();
		fillGrammarList(easyGrams, seqSets[0]);
		List<Grammar> medGrams = new LinkedList<Grammar>();
		fillGrammarList(medGrams, seqSets[1]);
		List<Grammar> hardGrams = new LinkedList<Grammar>();
		fillGrammarList(hardGrams, seqSets[2]);
		List<ggobiVariable> vars = new LinkedList<ggobiVariable>();
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "S_LS"));
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "L_dFd"));
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "F_dFd"));
		List<List<String>> easyVals = new LinkedList<List<String>>();
		for (Grammar g : easyGrams)
			easyVals.add(getXMLGrammarParams(g));
		List<List<String>> medVals = new LinkedList<List<String>>();
		for (Grammar g : medGrams)
			medVals.add(getXMLGrammarParams(g));
		List<List<String>> hardVals = new LinkedList<List<String>>();
		for (Grammar g : hardGrams)
			hardVals.add(getXMLGrammarParams(g));
		List<List<List<String>>> values = new LinkedList<List<List<String>>>();
		values.add(easyVals);
		values.add(medVals);
		values.add(hardVals);
		ggobi.outToXML(vars, values, out);
	}
	
	public static void outputGgobiXMLNuc(List<List<AlignedSequence>>[] seqSets, Display out) {
		if (seqSets == null || out == null)
			return;
		List<Grammar> easyGrams = new LinkedList<Grammar>();
		fillGrammarList(easyGrams, seqSets[0]);
		List<Grammar> medGrams = new LinkedList<Grammar>();
		fillGrammarList(medGrams, seqSets[1]);
		List<Grammar> hardGrams = new LinkedList<Grammar>();
		fillGrammarList(hardGrams, seqSets[2]);
		List<ggobiVariable> vars = new LinkedList<ggobiVariable>();
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "a"));
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "c"));
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "g"));
		vars.add(new ggobiVariable(ggobiVariable.VariableType.realvariable, "u"));
		List<List<String>> easyVals = new LinkedList<List<String>>();
		for (Grammar g : easyGrams)
			easyVals.add(getXMLNucDist(g));
		List<List<String>> medVals = new LinkedList<List<String>>();
		for (Grammar g : medGrams)
			medVals.add(getXMLNucDist(g));
		List<List<String>> hardVals = new LinkedList<List<String>>();
		for (Grammar g : hardGrams)
			hardVals.add(getXMLNucDist(g));
		List<List<List<String>>> values = new LinkedList<List<List<String>>>();
		values.add(easyVals);
		values.add(medVals);
		values.add(hardVals);
		ggobi.outToXML(vars, values, out);
	}
	
	private static List<String> getXMLGrammarParams(Grammar g) {
		List<String> rtn = new LinkedList<String>();
		iDouble[] pars = g.get_kh_params();
		iDouble one = new MyBigDecimal(1);
		rtn.add(one.sub(pars[0]).toPlainString());
		rtn.add(one.sub(pars[1]).toPlainString());
		rtn.add(one.sub(pars[2]).toPlainString());
		return rtn;
	}
	
	private static List<String> getXMLNucDist(Grammar g) {
		List<String> rtn = new LinkedList<String>();
		iDouble[] pars = g.get_nucleotide_dist();
		rtn.add(pars[0].toPlainString());
		rtn.add(pars[1].toPlainString());
		rtn.add(pars[2].toPlainString());
		rtn.add(pars[3].toPlainString());
		return rtn;
	}
	
	private static void fillGrammarList(List<Grammar> list, List<List<AlignedSequence>> seqSets) {
		for (List<AlignedSequence> set : seqSets) {
			Grammar g = new PfoldGrammar();
			for (AlignedSequence seq : set)
				g.add(seq.getStructure("refrence").getStructure(), seq.getSequence());
			list.add(g);
		}
	}
	
	public static void printQuickResults(List<AlignedSequence>[] setsArr) {
		Grammar g;
		String[] diff = { "Easy", "Medium", "Hard" };
		for (int i=0;i<setsArr.length;i++) {
			int minNUN = Integer.MAX_VALUE;
			int minHel = Integer.MAX_VALUE;
			int maxNUN = -1;
			int maxHel = -1;
			double avgNUN = 0;
			double avgHel = 0;
			for (AlignedSequence seq : setsArr[i]) {
				g = new PfoldGrammar();
				g.add(seq.getStructure("refrence").getStructure(), seq.getSequence());
				int NUN = g.getNUN();
				int Hel = g.getCountsArray().get("L_dFd");
				minNUN = minNUN < NUN ? minNUN : NUN;
				maxNUN = maxNUN > NUN ? maxNUN : NUN;
				avgNUN += NUN;
				minHel = minHel < Hel ? minHel : Hel;
				maxHel = maxHel > Hel ? maxHel : Hel;
				avgHel += Hel;
			}
			avgNUN /= setsArr[i].size();
			avgHel /= setsArr[i].size();
			System.out.println(diff[i]);
			System.out.println("Min NUN: " + minNUN);
			System.out.println("Max NUN: " + maxNUN);
			System.out.println("Avg NUN: " + avgNUN);
			System.out.println("Min Hel: " + minHel);
			System.out.println("Max Hel: " + maxHel);
			System.out.println("Avg Hel: " + avgHel);
			System.out.println("\n");
		}
	}
}
